/*****************************************************************************
 *   Copyright (C) 2008 John Schember <john@nachtimwald.com>                 *
 *                                                                           *
 *   This file is part of niwbillmanager.                                    *
 *                                                                           *
 *   niwbillmanager is free software: you can redistribute it and/or         *
 *   modify it under the terms of the GNU General Public License as          *
 *   published by the Free Software Foundation, either version 3 of the      *
 *   License, or (at your option) any later version.                         *
 *                                                                           *
 *   niwbillmanager is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
 *   GNU General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with niwbillmanager. If not, see                                  *
 *   <http://www.gnu.org/licenses/>.                                         *
 *****************************************************************************/

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QFileInfoList>
#include <QPluginLoader>

#include "../../constants.h"

#include "pluginmanager.h"
#include "mainwindow.h"

PluginManager::PluginManager(MainWindow *parent, NiwBillManager *lib)
{
    m_parent = parent;
    m_lib = lib;
    findPlugins();
}

PluginManager::~PluginManager()
{
    Q_FOREACH (Plugin *plugin, m_plugins) {
        delete plugin;
    }
    m_plugins.clear();
}

void PluginManager::enablePlugin(QString name)
{
    if (!getPlugin(name)->isEnabled()) {
        getPlugin(name)->loadPlugin(m_lib);
        m_parent->getToolsMenu()->addAction(getPlugin(name)->
            getPluginInterface()->getAction());

        QObject::connect(getPlugin(name)->getPluginInterface(),
            SIGNAL(uiUpdate()), m_parent, SLOT(uiUpdated()));
        QObject::connect(getPlugin(name)->getPluginInterface(),
            SIGNAL(billItemsChange()), m_parent, SLOT(billItemsChanged()));
        QObject::connect(getPlugin(name)->getPluginInterface(),
            SIGNAL(tagsChange()), m_parent, SLOT(tagsChanged()));
        QObject::connect(getPlugin(name)->getPluginInterface(),
            SIGNAL(undoRedoUpdate()), m_parent, SLOT(undoRedoUpdated()));

        QObject::connect(getPlugin(name)->getPluginInterface()->getAction(),
            SIGNAL(triggered()), getPlugin(name)->getPluginInterface(),
            SLOT(on_actionRun_triggered()));

        getPlugin(name)->setEnabled(true);
    }
}

void PluginManager::disablePlugin(QString name)
{
    if (getPlugin(name)->isEnabled()) {
        m_parent->getToolsMenu()->removeAction(getPlugin(name)->
            getPluginInterface()->getAction());

        QObject::disconnect(getPlugin(name)->getPluginInterface(),
            SIGNAL(uiUpdate()), m_parent, SLOT(uiUpdated()));
        QObject::disconnect(getPlugin(name)->getPluginInterface(),
            SIGNAL(billItemsChange()), m_parent, SLOT(billItemsChanged()));
        QObject::disconnect(getPlugin(name)->getPluginInterface(),
            SIGNAL(tagsChange()), m_parent, SLOT(tagsChanged()));
        QObject::disconnect(getPlugin(name)->getPluginInterface(),
            SIGNAL(undoRedoUpdate()), m_parent, SLOT(undoRedoUpdated()));

        QObject::disconnect(getPlugin(name)->getPluginInterface()->getAction(),
            SIGNAL(triggered()), getPlugin(name)->getPluginInterface(),
            SLOT(on_actionRun_triggered()));

        getPlugin(name)->unloadPlugin();
        getPlugin(name)->setEnabled(false);
    }
}

QSet<QString> PluginManager::getAllPlugins()
{
    return m_plugins.uniqueKeys().toSet();
}

QSet<QString> PluginManager::getEnabledPlugins()
{
    QSet<QString> enablePlugins;

    Q_FOREACH (Plugin *plugin, m_plugins) {
        if (plugin->isEnabled()) {
            enablePlugins.insert(plugin->getName());
        }
    }

    return enablePlugins;
}

Plugin *PluginManager::getPlugin(QString name)
{
    if (m_plugins.contains(name)) {
        return m_plugins.value(name);
    }

    return 0;
}

void PluginManager::findPlugins()
{
    QStringList PluginPaths;
    PluginPaths << Constants::PluginPath
        << QCoreApplication::applicationDirPath() + "/plugins";

    QDir dir;
    dir.setFilter(QDir::Readable | QDir::Files | QDir::NoDotAndDotDot);
    dir.setSorting(QDir::Name);

    QPluginLoader pluginLoader;

    Q_FOREACH (QString path, PluginPaths) {
        if (QFile::exists(path)) {
            dir.setPath(path);

            QFileInfoList list = dir.entryInfoList();
            Q_FOREACH (QFileInfo file, list) {
                pluginLoader.setFileName(file.absoluteFilePath());
                if (pluginLoader.load()) {
                    Qt4UiPluginInterface *loadedPlugin;

                    loadedPlugin = qobject_cast<Qt4UiPluginInterface *>
                        (pluginLoader.instance());

                    if (loadedPlugin) {
                        Plugin *plugin = new Plugin();

                        plugin->setName(loadedPlugin->getName());
                        plugin->setCredits(loadedPlugin->getCredits());
                        plugin->setDescription(loadedPlugin->getDescription());
                        plugin->setVersion(loadedPlugin->getVersion());
                        plugin->setLicense(loadedPlugin->getLicense());
                        plugin->setLocation(file.absoluteFilePath());

                        m_plugins.insert(plugin->getName(), plugin);
                    }

                    pluginLoader.unload();
                }
            }
        }
    }
}
